#ifndef _GSOLVERBBPV3NOWAITMASTER_H_
#define _GSOLVERBBPV3NOWAITMASTER_H_

#include <list>

#include "gsolverBBPv3NoWait.h"

#include "gsupplyLinkProblem.h"
#include "gsupplyLinkSolution.h"
#include "gsearchnode.h"
#include "gchrono.h"





/**
 *
 */
class SlaveChrono : public gchrono {
 private:
  int depthLevel ;
  int state ; // 1 activated ; 0 deactivated

 public:
  inline virtual void start() {state = 1 ; gchrono::start() ; }
  inline virtual void stop() { gchrono::stop() ; }
  inline void deactivate() { state = 0 ; }
  inline int  isActivated() { return state ; }

  friend class GSolverBBPv3NoWaitMaster ;
} ;




/**
 *
 */
class SearchTreeExploringTimeStat {
 private:
  int depthLevel ;
  
  int    nbrStats ;
  double totalTime,meanTime ;
  
 public:
  SearchTreeExploringTimeStat():nbrStats(0),totalTime(0.0),meanTime(-1.0) {}
  void addStat(double time) { totalTime+=time ; nbrStats++ ; meanTime = totalTime/(double)nbrStats;}
  inline double getMeanTime() { return meanTime ;}
  inline int getNbrStats() { return nbrStats ;}
  
  friend class GSolverBBPv3NoWaitMaster ;
} ;





/* #define COLLECT_TIME_STATISTICS_STATE_INIT      0 */
/* #define COLLECT_TIME_STATISTICS_STATE_START     1 */
/* #define COLLECT_TIME_STATISTICS_STATE_STOP      2 */

/**
 * A BBP solver : starts with jobs with last due dates
 *
 * Dans cette version 3 de la BBP, on demarre avec les jobs reordonnes dans le sens des dates dues croissantes. Mais
 * contrairement a l'exploration brutale de la version 2, cette fois on ne considere pas n'importe quel numero de batch.
 * Pour chaque job, on choisit de le rajouter soit dans un batch deja existant dont la capacite residuel est suffisante
 * pour stocker le nouveau job, soit dans un nouveau batch.
 *
 * Le nouveau batch est ordonnance avant les autres batchs deja crees.
 *
 * ATTENTION : Pour que cette solution soit optimale, sachant que l'on
 * part d'un probleme pour lequel les jobs sont classes par date due croissante, il est egalement necessaire que le cout de stockage
 * de tous les jobs soient identiques. Dans le cas contraire, la solution ainsi construite n'est plus certaine d'etre optimale.
 */
class GSolverBBPv3NoWaitMaster : public GSolverBBPv3NoWait {
 private:

#ifdef GMPI
  MPI_Request request_bestevalfromslave ;
  MPI_Request request_endworkfromslave ;
  MPI_Request request_workfromslave ;
  MPI_Request request_besteval[MAX_SLAVES] ;

  // Number of waiting slaves
  int nbrWaitingSlaves ;
  int maxWaitingSlaves ;
  int slaveIsWaiting[MAX_SLAVES] ;

  // list of search tree nodes to dispatch to the computing nodes
  list<searchnode> listSearchNodes ;  
  int listSearchNodesMaxSize ;
#endif
  
  /**
   *  Time to explore entirely the search tree from a tree node at a given depth level (the indice of the array) 
   *  to the last depth level.
   *
   *  searchTreeExploringTime[0] = total time to explore the entire search tree
   */
  SlaveChrono slaveChrono[MAX_SLAVES] ;
  SearchTreeExploringTimeStat searchTreeStat[MAX_SEARCHTREE_DEPTH] ;
  /* int collectTimeStatisticsState ; */

 public:
  GSolverBBPv3NoWaitMaster(GSupplyLinkProblem& pb, int node_, int p_=0) ;
  virtual ~GSolverBBPv3NoWaitMaster() {} 
  
  virtual void solveInit() ;
  virtual void solveMain() ;

#ifdef GMPI
  void    testForBestEvalMsgFromSlave() ;
  int     testForEndWorkMsgFromSlave() ;

  void    dispatchWorkToSlave() ;
#endif

  // check the MPI communication is different
  virtual void testForMPIComm() ;

  // the work to do when a better solution is found
  virtual void sendMPICommForBestSolution(double, double) ;

  // the work to do before exploring further the search tree
  virtual int pushWork(searchnode& treenodechild) ;
  virtual int dispatchWork() ;

  //  void    depthFirstSearch(const searchnode&) ;

} ;

#endif
